package locadora.negocio.pessoas;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;




import locadora.dados.RepositorioItem;
import locadora.dados.RepositorioPessoa;
import locadora.negocio.Devolucao;
import locadora.negocio.Emprestimo;
import locadora.negocio.GerenciamentoItens;
import locadora.negocio.GerenciamentoPessoas;
import locadora.negocio.produtos.Item;
import miscelanea.Data;

public class Funcionario extends Pessoa implements Serializable, GerenciamentoPessoas, GerenciamentoItens{

	private static final long serialVersionUID = 1L;
	
	private int metaDeLocacoes;
	private int locacoesRealizadasNoPeriodo;
	private ArrayList<Data> periodoDaMeta;

	/**
	 * Cria uma instância de um Funcionario, exatamente como se faz no tipo Pessoa
	 * @param nome nome da pessoa
	 * @param dataNascimento data de nascimento da pessoa
	 * @param identidade número da identidade no formato XXXXX, onde X é um algarismo
	 * @param orgaoExpedidor nome do órgão expedidor
	 * @param CPF número do CPF no formato XXXXXXXXXXX, no qual X é um algarismo
	 * @param logradouro nome do logradouro
	 * @param CEP CEP no formato XXXXXXXX, no qual X é um algarismo
	 * @param bairro nome do bairro
	 * @param cidade nome da cidade
	 * @param estado nome do estado
	 */
	public Funcionario(String nome, Data dataNascimento, String identidade, String orgaoExpedidor, String CPF, String logradouro, String CEP, String bairro, String cidade, String estado) throws Exception {
		super(nome, dataNascimento, identidade, orgaoExpedidor, CPF, logradouro, CEP, bairro, cidade, estado);
		this.metaDeLocacoes = 0;
		this.periodoDaMeta = new ArrayList<Data>();
		this.locacoesRealizadasNoPeriodo = 0;
	}

	/**
	 * Retorna a meta definida para determinado período
	 * @return meta de locações
	 */
	public int getMetaDeLocacoes() {
		return metaDeLocacoes;
	}

	/**
	 * Define o número de locações a serem realizadas para se atingirem as metas
	 * @param metaDeLocacoes 
	 */
	public void setMetaDeLocacoes(int metaDeLocacoes) {
		this.metaDeLocacoes = metaDeLocacoes;
	}

	/**
	 * Retorna o período da meta como uma array definindo o início e o fim do mesmo.
	 * @return
	 */
	public ArrayList<Data> getPeriodoDaMeta() {
		return periodoDaMeta;
	}

	/**
	 * Define as datas de início e fim do período de cumprimento das metas
	 * @param inicio data de inicio no formato ddmmaaa para cumprir as metas estabelecidas
	 * @param fim data fim no formato ddmmaaa para cumprir as metas estabelecidas
	 * @throws Exception
	 */
	public void setPeriodoDaMeta(String inicio, String fim) throws Exception {
		this.periodoDaMeta.add(new Data(inicio));
		this.periodoDaMeta.add(new Data(fim));
	}
	
	/**
	 * Retorna o número de locações que o funcionário realizou no período da meta
	 * @return
	 */
	public int getLocacoesNoPeriodoDaMeta() {
		return locacoesRealizadasNoPeriodo;
	}

	/**
	 * Define o número de locações realizadas no período da meta
	 * @param locacoesNoPeriodoDaMeta número de locações
	 */
	public void setLocacoesNoPeriodoDaMeta(int locacoesNoPeriodoDaMeta){
		this.locacoesRealizadasNoPeriodo = locacoesNoPeriodoDaMeta;
	}

	/**
	 * Adiciona um Cliente
	 * @param pessoa pessoa a adicionar
	 * @throws Exception caso se tente adicionar uma instância que não seja um Cliente ou mesmo uma Pessoa
	 * que já esteja cadastrada uma exceção é levantada indicando o tipo do erro
	 */
	public void adicionar(Pessoa pessoa) throws Exception{
		RepositorioPessoa repositorio = new RepositorioPessoa();
		//Se a pessoa a ser adicionada não existir no banco
		if(repositorio.busca(pessoa.getChave()) == null){
			//Um Funcionario pode adicionar um Cliente
			if(pessoa instanceof Cliente){
				repositorio.adiciona(pessoa);
			}else {
				throw new Exception("Você não possui privilégios para este tipo de operação!!");
			}
		}else{
			throw new Exception("Esta pessoa já está cadastrada!!");
		}
	}
	
	/**
	 * Remove um Cliente
	 * @param chave CPF da pessoa a ser removida
	 * @throws Exception caso se tente remover uma instância que não seja um Cliente ou mesmo uma Pessoa que não esteja cadastrada
	 * uma exceção é levantada indicando o tipo do erro
	 */
	public void removerPessoa(String chave) throws Exception{
		RepositorioPessoa repositorio = new RepositorioPessoa();
		Pessoa pessoa;
		//Se a pessoa a ser removida existir no banco de dados
		if((pessoa = repositorio.busca(chave)) != null){
			//Um Funcionario pode remover um cliente
			if(pessoa instanceof Cliente){
				repositorio.remove(chave);
			}else {
				throw new Exception("Você não possui privilégios para este tipo de operação!!");
			}
		}else{
			throw new Exception("Esta pessoa não está cadastrada!!");
		}
	}

	/**
	 * Busca uma pessoa com este parâmetro e retorna um ponteiro para ela
	 * @param chave chave a ser buscada
	 * @return objeto buscado ou null
	 * @throws Exception 
	 */
	public Pessoa buscar(String chave) throws Exception {
		RepositorioPessoa repositorio = new RepositorioPessoa();
		return repositorio.busca(chave);
	}

	/**
	 * Passado um objeto do tipo Pessoa e sua atual chave, atualiza os dados do objeto de mesma chave contido na camada de dados.
	 * Este método é útil, inclusive, quando se deseja mudar um CPF cadastrado erroneamente.
	 * @param chave chave da Pessoa a ter os dados atualizados
	 * @param novosDadosPessoa objeto contendo todo o conjunto de dados a atualizar
	 */
	public void atualizar(String chave, Pessoa novosDadosPessoa) throws Exception {
		RepositorioPessoa repositorio = new RepositorioPessoa();
		Pessoa pessoa;
		//Se a pessoa a ser atualizada existir no banco de dados
		if((pessoa = repositorio.busca(chave)) != null){
			//Um Funcionario pode atualizar um cliente
			if(pessoa instanceof Cliente){
				pessoa.atualizar(novosDadosPessoa.getNome(), novosDadosPessoa.getDataNascimento(), novosDadosPessoa.getIdentidade(), 
						novosDadosPessoa.getExpedidor(), novosDadosPessoa.getCPF(), novosDadosPessoa.getLogradouro(), novosDadosPessoa.getCEP(),
						novosDadosPessoa.getBairro(), novosDadosPessoa.getCidade(), novosDadosPessoa.getEstado());
				((Cliente) pessoa).setPendencias(((Cliente)novosDadosPessoa).getPendencias());
				((Cliente) pessoa).setSituacaoFinanceira(((Cliente)novosDadosPessoa).getSituacaoFInanceira());
			}else {
				throw new Exception("Você não possui privilégios para este tipo de operação!!");
			}
		}else{
			throw new Exception("Esta pessoa não está cadastrada!!");
		}
	}

	@Override
	public Item buscarItem(String chave) throws FileNotFoundException, IOException, ClassNotFoundException {
		RepositorioItem repositorio = new RepositorioItem();
		return repositorio.busca(chave);
	}

	@Override
	public void adicionar(Item item) throws Exception {
		RepositorioItem repositorio = new RepositorioItem();
		repositorio.adiciona(item);
	}

	@Override
	public void removerItem(String chave) throws Exception {
		RepositorioItem repositorio = new RepositorioItem();
		//Se o Item a ser removido existir no banco
		if(repositorio.busca(chave) != null){
			repositorio.remove(chave);
		}else{
			throw new Exception("Este Item não está cadastrado!!");
		}
	}

	@Override
	public void atualizar(String chave, Item novosDadosItem) throws Exception {
		RepositorioItem repositorioItem = new RepositorioItem();
		RepositorioPessoa repositorioPessoa = new RepositorioPessoa();
		Item item;
		//Seo item a ser atualizado existir no banco de dados
		if(((item = repositorioItem.busca(chave)) != null)){
			//Se n'ao possuir nenhum locador cadastrado ou se possuir
			if((item.getLocador() == null) || (repositorioPessoa.busca(item.getLocador()) != null)){
				item.atualizar(item.getTitulo(), item.getNumMidias(), item.getAnoLancamento(), item.getDescricao(), item.getCusto(),
					item.getValorAluguel(), item.getLocador(), item.getDataLocacao(), item.getDataDevolucao());	
			}else{
				throw new Exception("Este Cliente não está cadastrado!!");
			}
		}else{
			throw new Exception("Este item não está cadastrado!!");
		}
		
	}

	@Override
	public void realizarEmprestimo(String chavePessoa, String chaveItem, Data dataLocacao, Data dataDevolucao) throws Exception {
		Emprestimo.alugarItem(chavePessoa, chaveItem, dataLocacao, dataDevolucao);
		this.locacoesRealizadasNoPeriodo++;
	}

	@Override
	public void devolverItem(String chavePessoa, String chaveItem, Data dataDevolucao, float adicionalPorAtraso, float credito) throws Exception {
		Devolucao.devolverItem(chavePessoa, chaveItem, dataDevolucao, adicionalPorAtraso, credito);
	}
	
	public String toString(){
		return (this.nome + "\n" + this.getChave() + "\n" + "meta para o período de " + this.periodoDaMeta.get(0) + 
				" a " + this.periodoDaMeta.get(1) + ": " + this.metaDeLocacoes + "\nmeta alcançada: " + this.locacoesRealizadasNoPeriodo +
					"\n");
	}

}
